package service

import (
	"errors"
	"io"
	"mime/multipart"
	"os"
	"store/config"
	"store/entity"
	"strings"

	"github.com/cihub/seelog"
	"github.com/google/uuid"
	"gorm.io/gorm"
)

// FileStoreService 文件存储service
type FileStoreService struct {
}

func (c *FileStoreService) getStorePath(fileID string) string {
	prefix := config.GetConfig().File.Prefix
	if !strings.HasSuffix(prefix, "/") {
		prefix = prefix + "/"
	}
	return prefix + fileID
}

// 检测存储服务是否可用
func (c *FileStoreService) check() (bool, error) {
	randomFilename := c.getStorePath(uuid.New().String())
	open, err := os.Create(randomFilename)
	result := false
	if nil == err {
		_, err = open.WriteString(randomFilename)
		if nil == err {
			err = open.Close()
			if nil == err {
				err = os.Remove(randomFilename)
				if nil == err {
					result = true
				}
			}
		}
	}
	return result, err
}

// CheckOrDown 检测存储服务是否有效,若无效,panic
func (c *FileStoreService) CheckOrDown() {
	res, err := c.check()
	if !res {
		msg := "存储地址不可用:" + err.Error()
		seelog.Error(msg)
		panic(msg)
	}
}

// Upload 上传文件
func (c *FileStoreService) Upload(file *multipart.FileHeader, fromIP string) (string, error) {
	fileID := uuid.New().String()
	errRes := entity.GetDb().Transaction(func(tx *gorm.DB) error {
		dst := c.getStorePath(fileID)
		src, err := file.Open()
		if nil == err {
			var out *os.File
			out, err = os.Create(dst)
			if nil == err {
				_, err = io.Copy(out, src)
				out.Close()
			}
			src.Close()
		}

		if nil == err {
			err = tx.Create(&entity.FileEntity{
				CommonEntity: entity.CommonEntity{
					ID: fileID,
				},
				Filename: &file.Filename,
				Size:     &file.Size,
				FromIP:   &fromIP,
			}).Error
		}

		if nil != err {
			os.Remove(dst)
		}
		return err
	})
	return fileID, errRes
}

// Get 获取文件
func (c *FileStoreService) Get(fileID string) (filePath string, filename string, err error) {
	fileEntity := entity.FileEntity{}
	fileEntity.FindByID(fileID)
	if "" != fileEntity.ID {
		filePath = c.getStorePath(fileID)
		filename = *fileEntity.Filename
		err = nil
	} else {
		err = errors.New("文件不存在")
	}
	return
}

// Delete 删除文件
func (c *FileStoreService) Delete(fileID string) {
	os.Remove(c.getStorePath(fileID))
	entity.GetDb().Delete(&entity.FileEntity{}, "id = ?", fileID)
}
